﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Collections.Concurrent;

namespace DotNetExtensions.Core.Mapper
{
    public class MapperConfigFactory : Singleton<MapperConfigFactory>
    {
        private ConcurrentDictionary<string, object> keyValuePairs = new ConcurrentDictionary<string, object>();
        public MapperConfig<TSource, TTarget> Get<TSource, TTarget>() where TSource : class where TTarget : class, new()
        {
            string key = typeof(TSource).FullName + "<>" + typeof(TTarget).FullName;
            if (keyValuePairs.TryGetValue(key, out object value))
            {
                return (value as MapperConfig<TSource, TTarget>);
            }
            return new MapperConfig<TSource, TTarget>();
        }
        public void Add<TSource, TTarget>(MapperConfig<TSource, TTarget> newValue) where TSource : class where TTarget : class, new()
        {
            string key = typeof(TSource).FullName + "<>" + typeof(TTarget).FullName;
            if (keyValuePairs.TryGetValue(key, out object value))
            {
                keyValuePairs.TryUpdate(key, newValue, value);
            }
            else
            {
                keyValuePairs.TryAdd(key, newValue);
            }
        }

        public static MapperConfig<TSource, TTarget> GetOrCreate<TSource, TTarget>() where TSource : class where TTarget : class, new()
        {
            return MapperConfigFactory.Default.Get<TSource, TTarget>();
        }
        public static void AddOrUpdte<TSource, TTarget>(MapperConfig<TSource, TTarget> newValue) where TSource : class where TTarget : class, new()
        {
            MapperConfigFactory.Default.Add<TSource, TTarget>(newValue);
        }
    }

    public class MapperConfig<TSource, TTarget> where TSource : class where TTarget : class, new()
    {
        /// <summary>
        /// 指定列转换
        /// </summary>
        public Action<TSource, TTarget> BindAction { get; set; }

        /// <summary>
        /// 忽略需要转换的列
        /// </summary>
        public List<string> IgnoreProperties { get; private set; }

        /// <summary>
        /// 是否转换枚举-整型
        /// </summary>
        public bool WithEnumInt { get; set; } = true;

        /// <summary>
        /// 是否转换Long和String
        /// </summary>
        public bool WithLongString { get; set; } = true;

        /// <summary>
        /// 非空0转可空时 将对方值设置为null
        /// </summary>
        public bool IgnoreNullableZore { get; set; } = true;

        /// <summary>
        /// 忽略大小写
        /// </summary>
        public bool IgnoreCase { get; set; }

        public void Bind(Action<TSource, TTarget> action)
        {
            BindAction = action;
        }


        public void Ignore(Expression<Func<TTarget, object>> expression)
        {
            LambdaExpression lambda = expression as LambdaExpression;
            if (lambda == null)
                throw new ArgumentNullException("method");

            MemberExpression memberExpr = null;

            if (lambda.Body.NodeType == ExpressionType.Convert)
            {
                memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
            }
            else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
            {
                memberExpr = lambda.Body as MemberExpression;
            }

            if (memberExpr == null)
                throw new ArgumentException("method");

            if (IgnoreProperties == null)
                IgnoreProperties = new List<string>();

            IgnoreProperties.Add(memberExpr.Member.Name);
        }
    }

}